package org.qydjk.console.shiro;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.qydjk.common.pojo.SRole;
import org.qydjk.common.pojo.SUser;
import org.qydjk.common.service.IBaseService;
import org.qydjk.common.shiro.ShiroByteSource;
import org.qydjk.common.shiro.vo.ShiroUser;
import org.qydjk.common.util.StringUtil;
import org.qydjk.console.constant.ConsoleConstant;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * @description：shiro权限认证
 */
public class ShiroDbRealm extends AuthorizingRealm {
    private static final Logger LOGGER = LogManager.getLogger(ShiroDbRealm.class);
    @Autowired
    private IBaseService baseService;
    
//    public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
//        super(cacheManager, matcher);
//    }
    
    /**
     * Shiro登录认证(原理：用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        LOGGER.info("Shiro开始登录认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

        SUser example = new SUser();
        example.setLoginName(token.getUsername());
        try {
            List<SUser> list = baseService.findByExample(example);
            // 账号不存在
            if (list == null || list.isEmpty()) {
                return null;
            }
            SUser user = list.get(0);
            // 账号未启用
            if (user.getStatus() == 1) {
                return null;
            }
            // 读取用户的url和角色
            Map<String, Set<String>> resourceMap = selectResourceMapByUserId(user.getId());
            Set<String> urls = resourceMap.get("urls");
            Set<String> roles = resourceMap.get("roles");
            ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getName(), urls);
            shiroUser.setRoles(roles);

            // 认证缓存信息
            return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(),
                    ShiroByteSource.of(user.getSalt()), getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private Map<String, Set<String>> selectResourceMapByUserId(Integer userId) throws Exception {
        Map<String, Set<String>> resourceMap = new HashMap<String, Set<String>>();
        List<SRole> roles = baseService.findBySQL("select sr.* from s_user_role sur left join s_role sr on sur.role_id = sr.id where sur.user_id = ?",SRole.class,userId);
        Set<String> urlSet = new HashSet<String>();
        Set<String> roleNames = new HashSet<String>();
        for (SRole role : roles) {
            List<Map<String, Object>> resourceList = null;
            if(role.getName().equals(ConsoleConstant.ADMINISTRATOR_ROLE_NAME)){
                resourceList = baseService.findMapBySQL("SELECT s.id AS id, s.url AS url FROM s_resource s");
            }else{
                 resourceList = baseService.findMapBySQL("SELECT e.id AS id, s.url AS url FROM s_role r LEFT JOIN s_role_resource e ON r.id = e.role_id LEFT JOIN s_resource s ON e.resource_id = s.id WHERE r.id = ?",role.getId());
            }
            if (resourceList != null) {
                for (Map<String, Object> map : resourceList) {
                    if (map.get("url") != null && !map.get("url").toString().equals("")) {
                        urlSet.add(map.get("url").toString());
                    }
                }
            }
            if (role != null) {
                roleNames.add(role.getName());
            }
        }
        resourceMap.put("urls", urlSet);
        resourceMap.put("roles", roleNames);
        return resourceMap;
    }

    /**
     * Shiro权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(shiroUser.getRoles());
        info.addStringPermissions(shiroUser.getUrlSet());
        
        return info;
    }
    
    @Override
    public void onLogout(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        removeUserCache(shiroUser);
    }

    /**
     * 清除用户缓存
     * @param shiroUser
     */
    public void removeUserCache(ShiroUser shiroUser){
        removeUserCache(shiroUser.getLoginName());
    }

    /**
     * 清除用户缓存
     * @param loginName
     */
    public void removeUserCache(String loginName){
        SimplePrincipalCollection principals = new SimplePrincipalCollection();
        principals.add(loginName, super.getName());
        super.clearCachedAuthenticationInfo(principals);
    }
}
